package framework.po;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

public class POBasePage {

    public String name;
    public HashMap<String,List<HashMap<String,Object>>> methods;

    public WebDriver driver;

  /*  public POBasePage(WebDriver driver) {
        this.driver = driver;
    }*/

    public static POBasePage load(String name,WebDriver driver) {

        POBasePage page=null;

        String path=String.format("src/test/java/framework/po/%s.yaml",name);
        if (new File(path).exists()){

            page=loadFromFile(path);
        }else {

            page=loadFromClassloader(name);

        }

        page.driver=driver;
        return page;

    }

    public static POBasePage loadFromFile(String path){
        ObjectMapper objectMapper=new ObjectMapper(new YAMLFactory());
        try {
            return objectMapper.readValue(new File(path), POBasePage.class);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static POBasePage loadFromClassloader(String className){
        /**
         * 利用反射冲生成page实例
         */
        try {
            return (POBasePage) Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            return null;
        }
    }

    public void runPOMethod(String methodName){

        if (methods == null){
            try {
                this.getClass().getMethod(methodName).invoke(this,null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return;
        }

        AtomicReference<By> default_by = new AtomicReference<>();

        methods.get(methodName).forEach(step->{
            step.entrySet().forEach(entry->{
                String action = entry.getKey().toLowerCase();
                Object value = entry.getValue();

                switch (action) {
                    case "get":
                        driver.get((String) value);
                        break;
                    case "find":
                        ArrayList<String> values = (ArrayList<String>) value;
                        String locator_by = values.get(0);
                        String locator_value = values.get(1);

                        if (locator_by.equals("id")) {
                            default_by.set(By.id(locator_value));
                        } else if (locator_by.equals("name")) {
                            default_by.set(By.name(locator_value));
                        } else if (locator_by.equals("css")) {
                            default_by.set(By.cssSelector(locator_value));
                        }else if (locator_by.equals("link_text")){
                            default_by.set(By.partialLinkText(locator_value));
                        }
                        break;
                    case "click":
                        click(default_by.get());
                        break;
                    case "sendkeys":
                        String keys= (String) value;
                        sendKeys(default_by.get(),keys);
                        break;
                    case "chrome":
                        driver=new ChromeDriver();
                        break;
                    case "wait_imp":
                        Integer seconds=(Integer) value;
                        driver.manage().timeouts().implicitlyWait(seconds, TimeUnit.SECONDS);
                        break;


                }

            });
                }
        );
    }

    public void click(By by) {
        try {
            driver.findElement(by).click();
        } catch (Exception e) {
            driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
            driver.findElement(by).click();
            e.printStackTrace();
        }

    }

    public void waitSecond() throws InterruptedException {
        Thread.sleep(5000);
    }

    public void sendKeys(By by, String content) {

        driver.findElement(by).sendKeys(content);
    }


    public boolean isDisplayed(By by) {
        return driver.findElement(by).isDisplayed();
    }

    public String getText(By by) {
        return driver.findElement(by).getText();
    }
}
